﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Emgu.CV;
using Emgu.CV.Structure;
using System.Drawing;
using uitocr.imaging;
using uitocr.imaging.Settings;
//using NeuronDotNet.Samples.CharacterRecognition;
using System.Threading.Tasks;
namespace uitocr.imaging.ContourAnalysisNS
{
    
    public class ImageProcessor
    {
        //settings
        public int analysisMethod = 1;
        int n = 10000;
        public bool doBinary = false;
        public bool automation = true;
        public bool checkinglost = false;
        public bool recoverMode = false;
        public bool BinarizeAdaptiveMethod = true;
        public bool equalizeHist = false;
        public bool noiseFilter = false;
        public int cannyThreshold = 50;
        public bool blur = false;
        public int adaptiveThresholdBlockSize = 4;
        public double adaptiveThresholdParameter = 1.2d;
        public bool addCanny = true;
        public bool filterContoursBySize = true;
        public bool onlyFindContours = false;
        public int minContourLength = 15;
        public int minContourArea = 10;
        public double minFormFactor = 0.5;
        //
        public  List<Blob> blob_collected = new List<Blob> ();
        public List<Contour<Point>> contours;
        public Templates templates = new Templates();
        public Templates samples = new Templates();
        public List<FoundTemplateDesc> foundTemplates = new List<FoundTemplateDesc>();
        public TemplateFinder finder = new TemplateFinder();
        public Image<Gray, byte> binarizedFrame;
        public Image<Gray, byte> SkeletonedFrame;
        public Image<Gray, byte> binarizedallFrame = null;
        public Image<Gray, byte> SkeletonedallFrame = null;
        public int numofObject = 1;
       // public Image<Graphics, byte>[] skeletonedFrameChild;
        public Blob[] blobCollection;
        public double NonAdaptiveThreshold = 220; // old is 220
        public bool dilate = true;
        public int dilateIteration = 1;
        public  scaleSize size = new scaleSize (80 , 80) ;
        public bool getBlobcollection = false;
        public bool analysis = false;
        public bool getskeleton = false;
        public bool getskeletonall = true;
        public bool getimageprocessed = true;
        public bool doresize;
        public bool blobfilter;
            
        enum Dimensions
        {
            Width,
            Height
            
        }
        enum AnchorPosition
        {
            Top,
            Center,
            Bottom,
            Left,
            Right
        }
        public  System.Drawing.Image fixedSizeImage(System.Drawing.Image imgToResize)
        {
            return FixedSize(imgToResize, size.Width, size.Height);
        }
        public  System.Drawing.Image FixedSize(System.Drawing.Image imgPhoto, int Width, int Height)
        {
            int sourceWidth = imgPhoto.Width;
            int sourceHeight = imgPhoto.Height;
            int sourceX = 0;
            int sourceY = 0;
            int destX = 0;
            int destY = 0;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            nPercentW = ((float)Width / (float)sourceWidth);
            nPercentH = ((float)Height / (float)sourceHeight);

            //if we have to pad the height pad both the top and the bottom
            //with the difference between the scaled height and the desired height
            if (nPercentH < nPercentW)
            {
                nPercent = nPercentH;
                destX = (int)((Width - (sourceWidth * nPercent)) / 2);
            }
            else
            {
                nPercent = nPercentW;
                destY = (int)((Height - (sourceHeight * nPercent)) / 2);
            }

            int destWidth = (int)(sourceWidth * nPercent);
            int destHeight = (int)(sourceHeight * nPercent);

            System.Drawing.Bitmap bmPhoto = new System.Drawing.Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

            System.Drawing.Graphics grPhoto = System.Drawing.Graphics.FromImage(bmPhoto);
            grPhoto.Clear(System.Drawing.Color.White);
            grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            grPhoto.DrawImage(imgPhoto,
                new System.Drawing.Rectangle(destX, destY, destWidth, destHeight),
                new System.Drawing.Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
                System.Drawing.GraphicsUnit.Pixel);

            grPhoto.Dispose();
            return bmPhoto;
        }
        
        public void ProcessImage(Image<Bgr, byte> frame)
        {
            ProcessImage(frame.Convert<Gray, Byte>());
            
        }
        
        

        
        public ImageProcessor(int analysisId) 
        {
            
            analysisMethod = analysisId;
            if (analysisId == 1) // for contour analysis!
            {
                
        equalizeHist = false;
         noiseFilter = false;
        cannyThreshold = 50;
         blur = true;
         adaptiveThresholdBlockSize = 4;
         adaptiveThresholdParameter = 1.2d;
         addCanny = true;
         filterContoursBySize = true;
         onlyFindContours = false;
         minContourLength = 15;
         minContourArea = 10;
         minFormFactor = 0.5;
        //
                //
            } // that remain ANN and svm
            else
            {
                doBinary = true;
                automation = false;
                
                checkinglost = false;
                recoverMode = false;
                BinarizeAdaptiveMethod = false;
                equalizeHist = false;
                noiseFilter = false;
                blur = false;
                NonAdaptiveThreshold = 220; // old is 220
                dilate = false;
        
            }

        

        }
        public void ProcessImage(Bitmap frame)
        {
            ProcessImage(new Image<Bgr, byte>(frame));
            
        }
        public void DocumentSkew(ref Image<Gray ,byte> image)
        {

        }
        public void ProcessImage(Image<Gray, byte> grayFrame)
        {
            if (this.analysisMethod == 1) // contour ananlysis
                ProcessImage2(grayFrame);
            else // ann and svm
                ProcessImage1(grayFrame);
        }
        public ImageProcessor(Setting setting_)
        {
            this.analysis = setting_.analysis_;
            this.analysisMethod = setting_.analysisID;
            this.BinarizeAdaptiveMethod = setting_.binayAdaptiveMethod;
            this.checkinglost = setting_.LostChecking;
            this.doBinary = setting_.dobinary;
            this.equalizeHist = setting_.equalize_Hist;
            this.dilateIteration = setting_.dilateIteration;
            this.dilate = setting_.dialte;
            this.noiseFilter = setting_.noiseFilter;
            this.numofObject = setting_.numberofObject;
            this.blur = setting_.blur;
            this.recoverMode = setting_.recoverMode;
            this.getskeleton = setting_.getsekeleton;
            this.getBlobcollection = setting_.getblobcollection;
            this.NonAdaptiveThreshold = setting_.nonadaptivethreshold;
            this.size = setting_.size;
        }
        public void process(Image<Bgr, byte> grayframe , Setting setting_   )
        {
            ImageProcessor imgp;
            if (setting_.numberofObject == 1)
            {
                Setting st = new Setting();
                st.nonadaptivethreshold = setting_.nonadaptivethreshold;
                imgp = new ImageProcessor(st);
                
                //
                
                

                imgp.ProcessImage(grayframe);
                // obtain object collection in processed image 
                BlobCounter blobct = new BlobCounter();
                blobct.ObjectsOrder = ObjectsOrder.YX;
                blobct.MinHeight = 7;
                blobct.MinWidth = 7;
                
                
                //imgp.binarizedFrame.ToBitmap().Save("ak1.png");
                blobct.ProcessImage(imgp.binarizedFrame.ToBitmap());
                imgp.binarizedFrame.ToBitmap().Save("haha.png");                
                
                
                Blob[] blobcollections = blobct.GetObjects(imgp.binarizedFrame.ToBitmap(), false);
                
                imgp = new ImageProcessor(setting_);
                int name = 1;

                
                
                foreach(Blob blob_ in blobcollections )
                {

                    Rectangle objectRect = blob_.Rectangle;
                    int obWidth = objectRect.Width;
                    int obHeight = objectRect.Height;

                    int left = objectRect.X;
                    int top = objectRect.Y;

                    Bitmap blob_image = blob_.Image.ToManagedImage();
                    Invert inv = new Invert();
                    blob_image = inv.Apply(blob_image);

                    Bitmap objectmap = new Bitmap(obWidth + 2, obHeight + 2, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                    for (int t = 0; t < obHeight + 2; t++)
                        for (int c = 0; c < obWidth + 2; c++)
                        {
                            objectmap.SetPixel(c, t, c > 0 && t > 0 && c < obWidth + 1 && t < obHeight + 1 ? blob_image.GetPixel(c - 1, t - 1) : Color.FromArgb(255, 255, 255));
                        }



                    //objectmap = grayframe.ToBitmap().Clone(new Rectangle(objectRect.X - 2, objectRect.Y - 2, obWidth + 2, obHeight + 2), System.Drawing.Imaging.PixelFormat.Format24bppRgb);

                    if (setting_.Do_resize)
                    {
                        if (obWidth / 20 < 1 && obHeight / 20 < 1)

                            objectmap = (Bitmap)FixedSize(objectmap, setting_.size.Width, setting_.size.Height);
                    }
                    //else objectmap = (Bitmap)Preprocess.Process.fixedSizeImage(objectmap);

                    imgp.checkinglost = true;
                    //objectmap.Save(name.ToString("0") + "dumamay.png");
                    imgp.ProcessImage(objectmap);
                    blob_.Label = imgp.blobCollection[0].Label;
                    //objectmap.Save("dumamay.png");

                    //imgp.SkeletonedFrame.ToBitmap().Save(name.ToString("000") + "oin.png");
                    name++;
                    //imgp.binarizedFrame.ToBitmap().Save("hehe.png");

                    blob_collected.Add(blob_);
                
                }
                    
                
            }

            else
            {
                this.numofObject = 2;
                ProcessImage(grayframe);
            }
            
        }
        public void ProcessImage1(Image<Gray, byte> grayFrame)
        {
           //recover();
                /*
            Image<Gray, byte> temp = grayFrame; ;
            DocumentSkew(ref temp);
            grayFrame = temp;
                 * */
            

            if (this.equalizeHist)
            grayFrame._EqualizeHist();//autocontrast
            
            //dest_ = src2.Sub(src1);
            //dest_.Save("dest21.bmp");

            //smoothed
            
            Image<Gray, byte> smoothedGrayFrame = grayFrame.PyrDown();
            smoothedGrayFrame = smoothedGrayFrame.PyrUp();
            
            
            //canny
            Image<Gray, byte> cannyFrame = null;
            if (this.noiseFilter)
                cannyFrame = smoothedGrayFrame.Canny(new Gray(cannyThreshold), new Gray(cannyThreshold));

            //smoothing
            if (this.blur)
                grayFrame = smoothedGrayFrame;
            
            //binarize
            if (this.doBinary)
            {
                if (BinarizeAdaptiveMethod)
                    // grayFrame.Bitmap = new Threshold(230).Apply(grayFrame.ToBitmap());

                    CvInvoke.cvAdaptiveThreshold(grayFrame, grayFrame, 255, Emgu.CV.CvEnum.ADAPTIVE_THRESHOLD_TYPE.CV_ADAPTIVE_THRESH_MEAN_C, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY, adaptiveThresholdBlockSize + adaptiveThresholdBlockSize % 2 + 1, adaptiveThresholdParameter);
                else
                CvInvoke.cvThreshold(grayFrame, grayFrame, NonAdaptiveThreshold, 255, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY);
                    
            }
            
            grayFrame._Not();
            //grayFrame.Save("ss.bmp");
            //UnmanagedImage im;
            
            // before first diliate
            BlobCounter blbcounter = new BlobCounter();

            blbcounter.ObjectsOrder = ObjectsOrder.YX;
            if (blobfilter)
            {
                blbcounter.FilterBlobs = true;
                blbcounter.MinHeight = 10;
                blbcounter.MinWidth = 10;
            }
            
            blbcounter.ProcessImage(grayFrame.ToBitmap());
            //Contour c = grayFrame.FindContours();

            

            Blob[] blobcollective = blbcounter.GetObjects(grayFrame.ToBitmap(), true);
            //grayFrame.Save("0lacai.png");
            grayFrame._Not(); // for dilate operation
            //grayFrame.Save("zb.bmp");
            // begin first dilate - first dilate filter
            if (this.dilate)
            grayFrame._Dilate(dilateIteration);// best approach for second and third size of pen in ms paint is dilateIteration = 1
            // invert color . foreground - white , background - black 
            grayFrame._Not();
            //grayFrame.Save("zgray.bmp");
            //grayFrame.Save("ztestfat.bmp");
            // after dilate . get objects is existing  image
                        // compare new image with previous image that was create before first dilate operaion
            Image<Gray, byte> dest = grayFrame;
            
            
            // recover all blob that has lost all , they are blobs which width is less than 3 pixel , after dilate operation they will be lost
            //
            grayFrame.Save("0ohshit.png");
            if (this.checkinglost)
            {
                if (numofObject > 1)
                {
                    foreach (Blob vls in blobcollective)
                    {

                        if (Matching(vls, grayFrame.ToBitmap()) == vls.Area || Matching(vls, grayFrame.ToBitmap()) >= 70 * vls.Area / 100)
                            dest = dest.Add(new Image<Gray, byte>(vls.Image.ToManagedImage()));
                        
                        //grayFrame.Save("zi.bmp");
                    }
                }
                else
                {
                    BlobCounter blobcheck = new BlobCounter();
                    blobcheck.ProcessImage(grayFrame.ToBitmap());
                    
                    if (Matching(blobcollective[0], grayFrame.ToBitmap()) == blobcollective[0].Area || Matching(blobcollective[0], grayFrame.ToBitmap()) >= 40* blobcollective[0].Area / 100)
                        dest = dest.Add(new Image<Gray, byte>(blobcollective[0].Image.ToManagedImage()));
                    else if(blobcheck.GetObjectsInformation().Length != 1)
                        dest = dest.Add(new Image<Gray, byte>(blobcollective[0].Image.ToManagedImage()));
                }
            }

            // now dest image now is contain three kind of object
            /*
             *  1 . cracked objects , these objects are from one object , after dilate they have been broken to many part , and maybe lost some part to lost style 
             *  2 . primivte objects , these object  is still keep these style after dilate
             *  3 . non-primitive objects , these object weren't broke from parent object but they didn't keep  parent style any longer
             */
            
            
            //Blob[] newBlob = new Blob[vl.Length*2];
            if (recoverMode)
            {
                BlobCounter blbcounter2 = new BlobCounter();
                blbcounter2.ObjectsOrder = ObjectsOrder.YX;
                blbcounter2.ProcessImage(dest.ToBitmap());
                //save all object  
                Blob[] vl = blbcounter2.GetObjects(dest.ToBitmap(), true);
                Image<Gray, byte> blackground = new Image<Gray, byte>(dest.Width, dest.Height);
                foreach (Blob bl1 in blobcollective) // for each blob in image before dilating
                {
                    int count = 0;
                    blackground.SetValue(new Gray(0));
                    foreach (Blob bl2 in vl)
                    {
                        if (CheckInterSect(bl1.Image.ToManagedImage(), bl2.Image.ToManagedImage()))
                        {
                            blackground = blackground.Add(new Image<Gray, byte>(bl2.Image.ToManagedImage()));
                            count++;
                        }
                    }
                    if (count > 1) // bl1 was broke
                    {
                        bl1.Image.ToManagedImage().Save("f1.bmp");
                        // recover the parts have broken
                        // first recover the parts has lost after dilate , they are the pixel in bound of image
                        Image<Gray, byte> temp2 = blackground.Xor(new Image<Gray, byte>(bl1.Image.ToManagedImage()));
                        // process this image to recover the part have broken
                        //first scan all white pixel 
                        // for each pixel check sum of 8-neiborght , if less than 3 set it to black , else set to white
                        Bitmap bm1 = temp2.ToBitmap();

                        int inputWidth = bm1.Width;
                        int inputHeight = bm1.Height;
                        Bitmap bm2 = bm1.Clone(new System.Drawing.Rectangle(0, 0, inputWidth, inputHeight), System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                        byte[,] pixels = new byte[bm1.Height, bm1.Width];

                        for (int j = 0; j < inputHeight; ++j)
                        {
                            for (int i = 0; i < inputWidth; ++i)
                            {

                                if (bm1.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                                    pixels[j, i] = 1;
                                else
                                    pixels[j, i] = 0;
                            }
                        }

                        bm2.Save("dis2.bmp");
                        for (int j = 0; j < bm2.Height; j++)
                            for (int i = 0; i < bm2.Width; i++)
                            {
                                if (bm2.GetPixel(i, j) == Color.FromArgb(255, 255, 255))
                                {
                                    if (pixels[j - 1, i - 1] + pixels[j, i - 1] + pixels[j + 1, i - 1]
                                      + pixels[j - 1, i] + pixels[j + 1, i] + pixels[j - 1, i + 1]
                                    + pixels[j, i + 1] + pixels[j + 1, i + 1] < 4)

                                        bm2.SetPixel(i, j, Color.FromArgb(0, 0, 0));
                                }
                            }
                        bm2.Save("dis3.bmp");
                        // remove black hole
                        bl1.Image.ToManagedImage().Save("vkl.bmp");
                        for (int j = 0; j < inputHeight; ++j)
                        {
                            for (int i = 0; i < inputWidth; ++i)
                            {


                                if (bm2.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                                    pixels[j, i] = 1;
                                else
                                    pixels[j, i] = 0;
                            }
                        }
                        for (int j = 1; j < bm2.Height - 1; j++)
                            for (int i = 1; i < bm2.Width - 1; i++)
                            {

                                if (bm2.GetPixel(i, j) == Color.FromArgb(0, 0, 0))
                                {
                                    if (pixels[j - 1, i - 1] + pixels[j, i - 1] + pixels[j + 1, i - 1]
                                      + pixels[j - 1, i] + pixels[j + 1, i] + pixels[j - 1, i + 1]
                                    + pixels[j, i + 1] + pixels[j + 1, i + 1] == 7)
                                        bm2.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                                }

                            }
                        temp2.Save("dis.png");

                        // add pixel
                        bm2.Save("dis.png");
                        for (int j = 0; j < inputHeight; ++j)
                        {
                            for (int i = 0; i < inputWidth; ++i)
                            {

                                if (bm2.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                                    pixels[j, i] = 1;
                                else
                                    pixels[j, i] = 0;
                            }
                        }
                        for (int j = 1; j < bm2.Height - 1; j++)
                            for (int i = 1; i < bm2.Width - 1; i++)
                            {

                                if (bm2.GetPixel(i, j) == Color.FromArgb(255, 255, 255))
                                {

                                    if (pixels[j - 1, i] + pixels[j + 1, i] == 0 && pixels[j, i + 1] + pixels[j, i - 1] == 2)
                                    {

                                        bm2.SetPixel(i, j - 1, Color.FromArgb(255, 255, 255));
                                        bm2.SetPixel(i, j + 1, Color.FromArgb(255, 255, 255));

                                    }

                                    if (pixels[j, i + 1] + pixels[j, i - 1] == 0 && pixels[j - 1, i] + pixels[j + 1, i] == 2)
                                    {

                                        bm2.SetPixel(i + 1, j, Color.FromArgb(255, 255, 255));
                                        bm2.SetPixel(i - 1, j, Color.FromArgb(255, 255, 255));
                                    }
                                }
                            }
                        // remove spur

                        for (int j = 0; j < inputHeight; ++j)
                        {
                            for (int i = 0; i < inputWidth; ++i)
                            {

                                if (bm2.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                                    pixels[j, i] = 1;
                                else
                                    pixels[j, i] = 0;
                            }
                        }
                        for (int j = 1; j < bm2.Height - 1; j++)
                            for (int i = 1; i < bm2.Width - 1; i++)
                            {

                                if (bm2.GetPixel(i, j) == Color.FromArgb(255, 255, 255))
                                {
                                    if (pixels[j - 1, i - 1] + pixels[j, i - 1] + pixels[j + 1, i - 1]
                                      + pixels[j - 1, i] + pixels[j + 1, i] + pixels[j - 1, i + 1]
                                    + pixels[j, i + 1] + pixels[j + 1, i + 1] <= 3)
                                        bm2.SetPixel(i, j, Color.FromArgb(0, 0, 0));
                                }

                            }


                        Image<Gray, byte> finaldestination1 = new Image<Gray, byte>(bm2);

                        Image<Gray, byte> finaldestination2 = new Image<Gray, byte>(bl1.Image.ToManagedImage());

                        finaldestination2 = finaldestination1.Xor(finaldestination2);

                        dest = finaldestination1.Add(dest);

                    }
                }
            }
    
                // before the second dilate operation 

                /*
                //invert color
                grayFrame._Not();
                // the second dilate operation
                /*
                 *in this step , we will move all object that max its  pixel width <4
                 * all this object , after , will add to previous 
                 */
                // add canny
                /*
                if (!dilate)
                    grayFrame.Dilate(dilateIteration);
                if (addCanny)
                    if (cannyFrame != null)
                        grayFrame._Or(cannyFrame);
                */
                //grayFrame.Dilate(4);
                // obtain binarized image
            //int inputHeight_ = dest.Width;
            //int inputWidth_ = dest.Height;
            //int[,] pixels_ = new int[inputHeight_, inputWidth_];
            /*
            Bitmap bm22 = dest.Bitmap.Clone( new System.Drawing.Rectangle(0 , 0 ,inputWidth_ , inputHeight_) , System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            for (int j = 0; j < inputHeight_; ++j)
            {
                for (int i = 0; i < inputWidth_; ++i)
                {

                    if (bm22.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                        pixels_[j, i] = 1;
                    else
                        pixels_[j, i] = 0;
                }
            }
            for (int j = 1; j < bm22.Height - 1; j++)
                for (int i = 1; i < bm22.Width - 1; i++)
                {

                    if (bm22.GetPixel(i, j) == Color.FromArgb(255, 255, 255))
                    {
                        if (bm22.GetPixel(i, j) == Color.FromArgb(255, 255, 255))
                        {
                            if (pixels_[j - 1, i - 1] + pixels_[j, i - 1] + pixels_[j + 1, i - 1]
                              + pixels_[j - 1, i] + pixels_[j + 1, i] + pixels_[j - 1, i + 1]
                            + pixels_[j, i + 1] + pixels_[j + 1, i + 1] <= 3)
                                bm22.SetPixel(i, j, Color.FromArgb(0, 0, 0));
                        }

                        
                    }
                }
             
            dest = new Image<Gray, byte>(bm22);
             */

            this.binarizedFrame = dest;
            //dest.Save("ak.png");
            
            // now , skeleton binarized image
            if (getskeleton)
            {
                SkeletonedFrame = Skeleton(binarizedFrame);
                
            }
            
            /*
            if (!getskeletonall)
            {
                if (SkeletonedFrame != null)
                {
                    if (SkeletonedallFrame == null)
                        SkeletonedallFrame = SkeletonedFrame;
                    SkeletonedallFrame = SkeletonedallFrame.Add(this.SkeletonedFrame);
                }
            }
            if (!getimageprocessed)
            {
                if (binarizedFrame != null)
                    binarizedallFrame = binarizedFrame;
                    binarizedallFrame = binarizedallFrame.Add(binarizedFrame);
            }
             */ 
            //dilate canny contours for filtering
            // get blobs of skeletoned image
            if (getBlobcollection)
            {

                BlobCounter imgBlob = new BlobCounter();
                imgBlob.ObjectsOrder = ObjectsOrder.YX;
                imgBlob.ProcessImage(this.SkeletonedFrame.ToBitmap());
                blobCollection = imgBlob.GetObjects(SkeletonedFrame.ToBitmap(), true);
            
            }
            
            if(analysis)
            {
               NeuronDotNet.Samples.CharacterRecognition.MainForm  m = new NeuronDotNet.Samples.CharacterRecognition.MainForm();

                
                foreach (Blob bl in blobCollection)
                {
               bl.Label = m.Classify(bl.Image.ToManagedImage());
                    //bl.SkeletonedImage = bl.Image.ToManagedImage();
                //    blob_collected.Add(bl);
                }
                
            }
             
        }
        
        public bool CheckInterSect(Bitmap bm1 , Bitmap bm2)
        {
            
            for (int i = 0; i < bm1.Height; i++)
                    for (int j = 0; j < bm1.Width; j++)
                    {
                    if (bm1.GetPixel(j, i) == Color.FromArgb(255, 255, 255) && bm2.GetPixel(j, i) == Color.FromArgb(255, 255, 255))
                        return true;
                    }
            return false;
        }
        public int Matching(Blob bl , Bitmap bitmap)
        {
            int count = 0;// number of match pixels 
            
                Bitmap bm1 = bl.Image.ToManagedImage();
                for (int i = 0; i < bitmap.Height; i++)
                    for (int j = 0; j < bitmap.Width; j++)
                    {
                        /*
                        if (bm1.GetPixel(j, i) == Color.FromArgb(255, 255, 255))
                        {
                            Console.WriteLine(bm1.GetPixel(j, i).ToArgb() + " /" + i + "/ " + j);
                            Console.WriteLine(bitmap.GetPixel(j, i).ToArgb());
                        }
                         */
                        //bitmap.Save("z111111111.bmp");
                        if (bm1.GetPixel(j, i) == Color.FromArgb(255, 255, 255) && bitmap.GetPixel(j, i) == Color.FromArgb(0, 0, 0))
                            count++;
                        
                    }
            
                    return count;
        }
        
        public bool checkImageisOnePixelWidth(Bitmap bitmap)
        {
            
            byte[,] pixels = new byte[bitmap.Height, bitmap.Width];
            int inputWidth = bitmap.Width;
            int inputHeight = bitmap.Height;
            
            
            for (int j = 0; j < inputHeight; ++j)
            {
                for (int i = 0; i < inputWidth; ++i)
                {

                    if (bitmap.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                        pixels[j, i] = 1;
                    else
                        pixels[j ,i] = 0;
                }
            }
            /*
            System.Drawing.Bitmap bm = new System.Drawing.Bitmap(inputWidth, inputHeight);
            for (int i = 0; i < inputHeight ; i++)
                for (int j = 0; j < inputWidth ; j++)
                {
                    if (pixels[i, j] == 1)
                        bm.SetPixel(j, i, System.Drawing.Color.White);
                    else bm.SetPixel(j, i, System.Drawing.Color.Black);

                }
            bm.Save("vcl.bmp");
            */
            int flag = 0;
            for (int i = 0; i < inputHeight - 3; i++)
                for (int j = 0; j < inputWidth - 3; j++)
                    if (pixels[i, j] + pixels[i, j + 1] + pixels[i, j + 2]
                        + pixels[i + 1, j] + pixels[i + 1, j + 1] + pixels[i + 1, j + 2]
                        + pixels[i + 2, j] + pixels[i + 2, j + 1] + pixels[i + 2, j + 2] < 8)
                        flag++;
                        return false;
             return true;
        }
        public Image<Gray , byte> Skeleton(Bitmap frame)
        {
            return Skeleton(new Image<Gray, byte>(frame));
        }
        public Image<Gray , byte> Skeleton(Image<Gray ,byte> frame)
        {
            Bitmap bm = frame.ToBitmap();
            int inputWidth = bm.Width;
            int inputHeight = bm.Height;
            int[][] pixels = new int[inputWidth][];
            for (int i = 0; i < inputWidth; i++)
                pixels[i] = new int[inputHeight];
            for (int j = 0; j < inputHeight; ++j)
            {
                for (int i = 0; i < inputWidth; ++i)
                {

                    if (bm.GetPixel(i, j).ToArgb() == System.Drawing.Color.FromArgb(255, 255, 255).ToArgb())
                        pixels[i][j] = System.Drawing.Color.FromArgb(255, 255, 255).ToArgb();
                    else
                        pixels[i][j] = System.Drawing.Color.FromArgb(0, 0, 0).ToArgb();
                }
            }
            uitocr.imaging.Morphology.BinaryFast bin = new uitocr.imaging.Morphology.BinaryFast(pixels, inputWidth, inputHeight);
            uitocr.imaging.Morphology.Skeleton sk = new uitocr.imaging.Morphology.Skeleton();
            bin = sk.skeleton_image(bin);
            int[] k = new int[bm.Width * bm.Height];
            k = bin.convertToArray();
            bm = (System.Drawing.Bitmap)bm.Clone(new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            bin.generatePixels(bin.foregroundEdgePixels);
            for (int i = 0; i < bin.h; i++)
                for (int j = 0; j < bin.w; j++)
                    bm.SetPixel(j, i, System.Drawing.Color.FromArgb(k[i * bin.w + j]));


           return new Image<Gray, byte>(bm);
        }
        public void ProcessImage2(Image<Gray, byte> grayFrame)
        {
            if (equalizeHist)
                grayFrame._EqualizeHist();//autocontrast
            //smoothed
            Image<Gray, byte> smoothedGrayFrame = grayFrame.PyrDown();
            smoothedGrayFrame = smoothedGrayFrame.PyrUp();
            //canny
            Image<Gray, byte> cannyFrame = null;
            if (noiseFilter)
                cannyFrame = smoothedGrayFrame.Canny(new Gray(cannyThreshold), new Gray(cannyThreshold));
            //smoothing
            if (blur)
                grayFrame = smoothedGrayFrame;
            //binarize
            if (BinarizeAdaptiveMethod)
                CvInvoke.cvAdaptiveThreshold(grayFrame, grayFrame, 255, Emgu.CV.CvEnum.ADAPTIVE_THRESHOLD_TYPE.CV_ADAPTIVE_THRESH_MEAN_C, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY, adaptiveThresholdBlockSize + adaptiveThresholdBlockSize % 2 + 1, adaptiveThresholdParameter);
            else
                CvInvoke.cvThreshold(grayFrame, grayFrame, NonAdaptiveThreshold, 255, Emgu.CV.CvEnum.THRESH.CV_THRESH_BINARY);
            //
            grayFrame._Not();
            //
            if (addCanny)
                if (cannyFrame != null)
                    grayFrame._Or(cannyFrame);
            //
            this.binarizedFrame = grayFrame;

            //dilate canny contours for filtering
            if (cannyFrame != null)
                cannyFrame = cannyFrame.Dilate(3);

            //find contours
            var sourceContours = grayFrame.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_NONE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_LIST);
            //filter contours
            contours = FilterContours(sourceContours, cannyFrame, grayFrame.Width, grayFrame.Height);
            //find templates
            lock (foundTemplates)
                foundTemplates.Clear();
            samples.Clear();

            lock (templates)
                System.Threading.Tasks.Parallel.ForEach<Contour<Point>>(contours, (contour) =>
                {
                    var arr = contour.ToArray();
                    Template sample = new Template(arr, contour.Area, samples.templateSize);
                    lock (samples)
                        samples.Add(sample);

                    if (!onlyFindContours)
                    {
                        FoundTemplateDesc desc = finder.FindTemplate(templates, sample);

                        if (desc != null)
                            lock (foundTemplates)
                                foundTemplates.Add(desc);
                    }
                }
                );
            //
            FilterByIntersection(ref foundTemplates);
        }

        private static void FilterByIntersection(ref List<FoundTemplateDesc> templates)
        {
            //sort by area
            templates.Sort(new Comparison<FoundTemplateDesc>((t1, t2) => -t1.sample.contour.SourceBoundingRect.Area().CompareTo(t2.sample.contour.SourceBoundingRect.Area())));
            //exclude templates inside other templates
            HashSet<int> toDel = new HashSet<int>();
            for (int i = 0; i < templates.Count; i++)
            {
                if (toDel.Contains(i))
                    continue;
                Rectangle bigRect = templates[i].sample.contour.SourceBoundingRect;
                int bigArea = templates[i].sample.contour.SourceBoundingRect.Area();
                bigRect.Inflate(4, 4);
                for (int j = i + 1; j < templates.Count; j++)
                {
                    if (bigRect.Contains(templates[j].sample.contour.SourceBoundingRect))
                    {
                        double a = templates[j].sample.contour.SourceBoundingRect.Area();
                        if (a / bigArea > 0.9d)
                        {
                            //choose template by rate
                            if (templates[i].rate > templates[j].rate)
                                toDel.Add(j);
                            else
                                toDel.Add(i);
                        }
                        else//delete tempate
                            toDel.Add(j);
                    }
                }
            }
            List<FoundTemplateDesc> newTemplates = new List<FoundTemplateDesc>();
            for (int i = 0; i < templates.Count; i++)
                if (!toDel.Contains(i))
                    newTemplates.Add(templates[i]);
            templates = newTemplates;
        }

        private List<Contour<Point>> FilterContours(Contour<Point> contours, Image<Gray, byte> cannyFrame, int frameWidth, int frameHeight)
        {
            int maxArea = frameWidth * frameHeight / 5;
            var c = contours;
            
                
            List<Contour<Point>> result = new List<Contour<Point>>();
            while (c != null)
            {
                if (filterContoursBySize)
                    if (c.Total < minContourLength ||
                        c.Area < minContourArea || c.Area > maxArea ||
                        c.Area / c.Total <= minFormFactor)
                        goto next;

                if (noiseFilter)
                {
                    Point p1 = c[0];
                    Point p2 = c[(c.Total / 2) % c.Total];
                    
                    if (cannyFrame[p1].Intensity <= double.Epsilon && cannyFrame[p2].Intensity <= double.Epsilon)
                        goto next;
                }
                result.Add(c);

            next:
                c = c.HNext;
            }

            return result;
        }
    }
}
